import { unsafeWindow,mkApi} from "./monkeyApi" 
import { Crypto } from "persagy-tools";
import { ISystemConfig,IUserServiceForEncrypt ,I_response,I_config } from "./data-type"
import { routerApi } from "../../hooks/routers"
import { proxy } from "../ajaxHook/index"

// 加密类
const crypto = new Crypto({
  key: "1234123412ABCDEF",
  iv: "ABCDEF1234123412",
});

const consoleTip = true

const monkeyTool = {
  // 是否注入脚本
  inject(){
    // 先判断是否sassWeb代理页面
    const saasWebAvailable = mkApi.SAAS_WEB_DEBUG_AVAILABLE.get()
    const saasWebInfo = mkApi.SAAS_WEB_DEBUG_INFO.get()
    if(saasWebAvailable && saasWebInfo.targetUrl.includes(location.host)){
      return true
    }
    // 判断是否开启非开发页面显示
    let devToolVisible =  mkApi.DEVTOOL_VISIBLE.get()
    const localhostUrl = location.href.includes("localhost")
    if( devToolVisible || localhostUrl){
      return true
    }else{
      return false
    }
  },
  // 如果无路由信息或项目报错，不显示脚本
  visible(){
      // vue2中webpack报错
      let error = document.body.querySelector("#webpack-dev-server-client-overlay")
      if(error) return false
      // 处理项目开发报错的问题！
      let count = mkApi.ERROR_COUNT.get()
      if(count > 1){
        mkApi.ERROR_COUNT.set(0)
        return false
      }
      mkApi.ERROR_COUNT.set(count + 1)
      setTimeout(()=>{
        mkApi.ERROR_COUNT.set(0)
      },1000)
      // 根据是否有路由信息判断是否显示脚本
      const routerArrayInfo = routerApi.getRouterArrayInfo()
      if(routerArrayInfo.length > 0){
        return true
      }else{
        return false
      } 
  },
  registerMenuCommand(){
    mkApi.registerMenuCommand()
  },
}
const SAAS_WEB_API = {
  saas_webEnabled(){
    let enabled = true
    // 调试开关是否打开
    if(!mkApi.SAAS_WEB_DEBUG_AVAILABLE.get()) enabled = false
    if(!mkApi.SAAS_WEB_DEBUG_INFO.get().targetUrl) enabled = false
    if(location.href.includes("localhost")) enabled = false
    if(!localStorage.getItem("USER") ) enabled = false
    return enabled
  },
  PROXY_USER(){
    function getUser(){
      let user = localStorage.getItem("USER")
      let userInfo:IUserServiceForEncrypt = JSON.parse(crypto.Decrypt(user))
      consoleTip && console.log('【monkey】userInfo已经获取： ', userInfo);
      // 这里获取的userInfo可能已经被其他打开的页面修改过了，如果已经修改，我们需要使用系统库里面储存的userInfo信息
      if(userInfo.proxy){
        const ORIGIN_USER = mkApi.ORIGIN_USER.get()
        userInfo = JSON.parse(crypto.Decrypt(ORIGIN_USER))  
        consoleTip && console.log('【monkey】userInfo已经被其他打开页面修改，使用原始数据 ', userInfo);
      }else{
        const USER = crypto.Encrypt(JSON.stringify(userInfo))
        mkApi.ORIGIN_USER.set(USER)
        consoleTip && console.log('【monkey】userInfo为原始数据，储存至ORIGIN_USER中 ');
      }
      return userInfo
    }
    function setUser(userInfo:IUserServiceForEncrypt):void{
      let PROXY_USER =  crypto.Encrypt(JSON.stringify(userInfo))
      localStorage.setItem("USER",PROXY_USER)
      consoleTip && console.log('【monkey】localStorage USER 信息已经更新...');
    }
    function restoreUser(){
      // 登录界面刷新清除一些敏感信息
      if(location.href.includes("login")){
        localStorage.removeItem("USER")
      }
      if(localStorage.getItem("USER")){
        const ORIGIN_USER = mkApi.ORIGIN_USER.get()
        localStorage.setItem("USER",ORIGIN_USER)
      }
      consoleTip && console.log('【monkey】localStorage USER 信息还原完成...');
    }
    return {
      getUser,
      restoreUser,
      setUser,
    }
  },
  getEditUserInfo(userInfo:IUserServiceForEncrypt): IUserServiceForEncrypt {  
    userInfo.proxy = true
    if(!userInfo.user_id){
      userInfo.user_id = userInfo.userId
      consoleTip && console.log('【monkey】user_id不存在，使用userId进行兼容中...');
    }
    const saasWebInfo = mkApi.SAAS_WEB_DEBUG_INFO.get()
    // iframe的加载方式需要更改 uerInfo的显示名称，用于iframe链接拼接
    let isIframe = saasWebInfo.nestingType
    if(isIframe === "iframe"){
      userInfo.userName = this.getCurrentName(saasWebInfo.serverName)
    }
    let authorizations = userInfo.authorizations
    // 更改 子应用信息
    let localServeList = authorizations.filter(res => res.functionUrl && res.functionUrl.includes(saasWebInfo.serverName))
    if(localServeList.length > 0){
      const {otherRouter} = mkApi.SAAS_WEB_DEBUG_INFO.get()
      localServeList.forEach(res => {
        if(res.functionUrl && res.authorizationId && res.functionUrl.includes(saasWebInfo.serverName) && otherRouter?.length > 0 && otherRouter.some(item => item         .includes(res.authorizationId))){
          res.authorizationName = "【本地】" + res.authorizationName
        }
      })
    }
    // 如果服务已经部署生产
    if(localServeList.length > 0){
      //查看是否存在当前功能点 存在=> 替换此功能点 ； 不存在，插入此页面
      let findItem = localServeList.find(res => res.authorizationId && res.authorizationId.includes(saasWebInfo.authorizationId))
      if(findItem){
        consoleTip && console.log('【monkey】服务已经部署，查找到当前项目，替换中...');
        findItem.functionUrl = saasWebInfo.localUrl
        findItem.authorizationName = saasWebInfo.authorizationName ? saasWebInfo.authorizationName : findItem.authorizationName
      }else{
        consoleTip && console.log('【monkey】服务已经部署，但无当前项目，插入到第一个路由里去');
        let copyItem = JSON.parse(JSON.stringify(authorizations.find(res => res.functionUrl && res.productOrder === "1")))
        copyItem.functionUrl = saasWebInfo.localUrl
        copyItem.authorizationId = saasWebInfo.authorizationId
        copyItem.authorizationName = saasWebInfo.authorizationName ? saasWebInfo.authorizationName : `【本地代理服务】`
        authorizations.unshift(copyItem)
      }
    // 服务未部署生产
    }else{
      consoleTip && console.log('【monkey】服务未部署，添加项目中...');
      let firstItem = JSON.parse(JSON.stringify(authorizations.find(res => res.functionUrl && res.productOrder === "1")))   
      firstItem.authorizationId = saasWebInfo.authorizationId,
      firstItem.authorizationName = saasWebInfo.authorizationName || "【本地代理服务】" ,
      firstItem.functionUrl = saasWebInfo.localUrl
      authorizations.unshift( firstItem )
    }
    consoleTip && console.log('【monkey】userInfo已经修改完毕',userInfo);
    return userInfo
  },
  editSystemConfig():void{
    consoleTip && console.log('【monkey】 systemConfig 开始配置...');
    const systemConfig:ISystemConfig = (unsafeWindow as any)?.systemConfig
    if(!systemConfig) return consoleTip && console.log('【monkey】 未找到systemConfig ，配置失败！');
    const microAppIds = systemConfig.microAppIds 
    const hideHeader = systemConfig.hideHeader
    // const saasWebInfo = SAAS_WEB.get()
    const saasWebInfo = mkApi.SAAS_WEB_DEBUG_INFO.get()
    // 3.1嵌套方式改造
    const microAppIndex = microAppIds.findIndex(res => res === saasWebInfo.serverName)
    if(saasWebInfo.nestingType === "iframe"){
      microAppIndex > 0 && microAppIds.splice(microAppIndex,1)
    }else{
      microAppIndex === -1 && microAppIds.push(saasWebInfo.serverName)
    }
    // 3.2头部隐藏改造
    const microHideHeaderIndex = hideHeader.findIndex(res => res === saasWebInfo.authorizationId)
    if(saasWebInfo.hideHeader){
      microHideHeaderIndex === -1 &&  hideHeader.push(saasWebInfo.authorizationId) 
    }else{
      microHideHeaderIndex > 0 && hideHeader.splice(microAppIndex,1)
    }
    consoleTip && console.log('【monkey】 systemConfig 已经完成配置...',systemConfig);
  },
  urlFetch():void{
    const saasWebInfo = mkApi.SAAS_WEB_DEBUG_INFO.get() 
    if(saasWebInfo.nestingType === "qiankun"){
      consoleTip && console.log('【monkey】乾坤fetch请求拦截开始运行..... ');
      let realHook = unsafeWindow.fetch
      unsafeWindow.fetch = function(url:string){
        const status = url.includes(saasWebInfo.serverName) && !url.includes(saasWebInfo.localhost)
        if(status){
          const targetHost = new RegExp(location.origin,'g')
          consoleTip && console.log('【monkey】url替换中.....',url);
          url = (url as any).replace(targetHost,`http://${saasWebInfo.localhost}` )
        }
        return realHook(url)
      }
    }
  },
  getCurrentName(serverName:string):string{
    let searchValueList = mkApi.SEARCH_VALUE.get()
    if(!searchValueList || searchValueList.length === 0) {
      consoleTip && console.log('【monkey】未找到登录名，不能使用本地接口....');
      return serverName
    }
    let findItem = searchValueList.find((res:any)=> res.serverName === serverName)
    let loginName = ""
    if(!findItem && findItem.searchValue.includes("loginName=")){
      consoleTip && console.log('【monkey】未找到登录名，不能使用本地接口....');
      return serverName 
    }else{
      loginName = findItem.searchValue.split("=")[1]
    }
    return loginName
  }
}
const AJAX_HOOK_API= {
  nameServiceDataAPI(){
    let data = undefined
    function get(){
      return data
    }
    function set(userInfo:any){
      let newObj = {}
      let exceptList = ["authorizations","projects"]
      for(let key in userInfo){
        if(!exceptList.find(res => res === key)) {
          let newKey = key.replaceAll("_","").toLowerCase()            
          newObj[newKey] = userInfo[key]
        }
      }
      data = newObj
    }
    async function getPersonByUserNameService(loginName:string){
      const { localhost } = mkApi.SAAS_WEB_DEBUG_INFO.get()
      let url = `http://${localhost}/api/meos/EMS_SaaS_Web/Spring/MVC/entrance/unifier/getPersonByUserNameService`
      let body = {
        "user_id": "",
        "userId": "",
        "pd": "",
        "person_id": "",
        "personId": "",
        "puser": {
            "userId": "",
            "loginDevice": "PC",
            "pd": ""
        },
        "loginName":loginName,
        "loginDevice": "PC"
      }
      let data = await mkApi.GM_ajax(url,body)
      return data
    }
    return {
      get,set,getPersonByUserNameService
    }
  },
  setLocalAjax(config:I_config ):I_config{
    // 非代理页面，无需更改任何信息
    const {targetUrl,otherRouter} = mkApi.SAAS_WEB_DEBUG_INFO.get()
    if(!targetUrl.includes(location.host)) return config
    if(otherRouter?.length === 0 || !otherRouter.some(res => location.href.includes(res))) return config
    // 当前页面不包含子应用的其他路由时，也无需更改任何信息
    const saas_web_urlList = ["loginUserServiceForEncrypt","saveLog","sockjs-node","getpartitionProjects","getpartitionProjectsByUserId","queryBusinessBoardById"]
    if(saas_web_urlList.some(url => config.url.includes(url))) return config
    if(!config.url.includes("http")){
      const saasWebInfo = mkApi.SAAS_WEB_DEBUG_INFO.get() 
      if(config.url.startsWith("/")) {
        config.url = "http://" + saasWebInfo.localhost + config.url
      }else{
        config.url = "http://" + saasWebInfo.localhost + "/" + config.url
      }
    }
    // let responseData = JSON.parse(response.response)
    return config
  },
  editBody(body:any,userInfo:IUserServiceForEncrypt){
    let configBody = JSON.parse(body)
    for(let key in configBody){
      let newKey = key.replaceAll("_","").toLocaleLowerCase()
      if(userInfo.hasOwnProperty(newKey)){
        configBody[key] = userInfo[newKey]
      }
    }
    return JSON.stringify(configBody)
  },
  async setLocalAjaxBody(config:I_config ):Promise<I_config>{
    if(!config.url.includes("localhost")) return config
    let searchValueList = mkApi.SEARCH_VALUE.get()
    const { serverName } = mkApi.SAAS_WEB_DEBUG_INFO.get()
    let findItem = searchValueList.find((res:any)=> res.serverName === serverName)
    let loginName = ""
    if(!findItem && findItem.searchValue.includes("loginName=")){
      consoleTip && console.log('【monkey】未找到登录名，不能使用本地接口....');
      return config 
    }else{
      loginName = findItem.searchValue.split("=")[1]
    }
    let {get,set,getPersonByUserNameService} = this.nameServiceDataAPI()
    // 查找userinfo拦截接口
    let userInfo = get()
    if(!userInfo){
      try{
        let response = await getPersonByUserNameService(loginName)
        if(response){
          const responseData = JSON.parse(response)
          set(responseData.content[0])
          userInfo = get()
        }
      }catch(err){
        return config
      }
    }
    if(!userInfo) return config
    config.body = this.editBody(config.body,userInfo)
    return config
  },
  setLoginUserServiceForEncrypt(response:I_response):I_response{
    if(response.config.url.includes("loginUserServiceForEncrypt")){
      consoleTip && console.log('【monkey】登录接口已成功拦截，进行数据更改操作....');
      let responseData = JSON.parse(response.response)
      let userInfo:IUserServiceForEncrypt = responseData?.content[0]
      if(userInfo){
        const USER = crypto.Encrypt(JSON.stringify(userInfo))
        mkApi.ORIGIN_USER.set(USER)
        consoleTip && console.log('【monkey】将获取的原始信息储存至ORIGIN_USER中 ');
        userInfo = SAAS_WEB_API.getEditUserInfo(userInfo)
        // 更改响应信息
        response.response = JSON.stringify(responseData)
        return response
      }else{
        return response
      }
    }
    return response
  },
  unProxy(win?:any){
    win = win || unsafeWindow
    win.XMLHttpRequest = win.__xhr;
    win.__xhr = undefined;
  },
  ajax_hook_start(){
    proxy({
      //请求发起前进入
      onRequest: async (config:I_config, handler:any) => {
        config = this.setLocalAjax(config) || config
        config = await this.setLocalAjaxBody(config)
        handler.next(config);
      },
      //请求发生错误时进入，比如超时；注意，不包括http状态码错误，如404仍然会认为请求成功
      onError: (err:any, handler:any) => {
        console.log(err.type)
        handler.next(err)
      },
      //请求成功后进入
      onResponse: async (response:I_response, handler:any) => {
        response = this.setLoginUserServiceForEncrypt(response)
        handler.next(response)
      }
    },unsafeWindow)
  },
  ajax_enabled(){
    let proxyStatus = false
    let saasWebInfo = mkApi.SAAS_WEB_DEBUG_INFO.get()
    // 调试开启 && 当前为目标路径
    const saasWebAvailable = mkApi.SAAS_WEB_DEBUG_AVAILABLE.get()
    if(saasWebInfo.targetUrl && saasWebInfo.targetUrl.includes(location.host) && saasWebAvailable){
      // 主应用登录页面始终开启ajaxHook
      if(location.href.includes("login") || saasWebInfo.ajax){
        proxyStatus = true
      }else{
        proxyStatus = false
      }
    }
    return proxyStatus
  }
}
const hookStart = {
  ajaxStatus:false, // 是否已经开启ajax_hook
  saas_web_fetch_hook(){
    // sassweb 拦截原理（已登录）
      // 1.获取localStorage内储存的urlInfo信息
      // 2.更改urlInfo信息，并将原来的信息备份
      // 3.更改systemConfig配置信息
      // 4.将本地服务的请求链接进行更改
      // 5.页面销毁时，还原urlInfo信息
    const saas_webEnabled = SAAS_WEB_API.saas_webEnabled()
    consoleTip && console.log('【monkey】saas_webEnabled开启状态： ', saas_webEnabled);
    if(!saas_webEnabled) return
    const proxyUser = SAAS_WEB_API.PROXY_USER()
    const userInfo = proxyUser.getUser()
    if(userInfo.proxy){
      return consoleTip && console.log('【monkey】proxy已经修改！ ');
    }
    const  editUserInfo= SAAS_WEB_API.getEditUserInfo(userInfo)
    SAAS_WEB_API.editSystemConfig()
    proxyUser.setUser(editUserInfo)
    // 服务已经部署，但新项目未部署不开启urlFeTCh
   
    
    if(location.href.includes(( mkApi.SAAS_WEB_DEBUG_INFO.get().serverName))){
      const {otherRouter} = mkApi.SAAS_WEB_DEBUG_INFO.get()
      if(otherRouter && otherRouter?.length > 0 && otherRouter.some(res => location.href.includes(res))){
        SAAS_WEB_API.urlFetch()
      }
    }else{
      SAAS_WEB_API.urlFetch()
    }
    
  },
  xhr_Hook(){
    const enabled = AJAX_HOOK_API.ajax_enabled()
    consoleTip && console.log('【monkey】AJAX_HOOK开启状态',enabled);
    if(!enabled) return
    consoleTip && console.log('【monkey】接口拦截工具初始化中....');
    // 仅登录页面执行url拦截
    if( !this.ajaxStatus && location.href.includes("login") && !location.href.includes("localhost")){
      this.ajaxStatus = true
      SAAS_WEB_API.editSystemConfig()
      SAAS_WEB_API.urlFetch()
    }
    if((unsafeWindow as any).__xhr){
      AJAX_HOOK_API.unProxy()
      consoleTip && console.log('【monkey】清除网站自带hook工具，准备加载自定义hook工具....');
    }
    AJAX_HOOK_API.ajax_hook_start()
  }
}
function hookEnd(){
  const proxyUser = SAAS_WEB_API.PROXY_USER()
  unsafeWindow.addEventListener("unload",()=>{
    proxyUser.restoreUser()
    sessionStorage.clear()
  })
}


export {
  monkeyTool,
  hookStart,
  hookEnd
}
